#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
小超市结算系统 - 图形界面版
功能：支持商品录入、快速识别商品、计算费用、商品图片管理、商品ID自增、数据持久化
"""

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import os
import cv2
from PIL import Image, ImageTk
import datetime
import uuid
import json

class Product:
    """商品类，存储商品信息"""
    def __init__(self, product_id, name, price, barcode=None, image_path=None):
        self.product_id = product_id  # 商品ID
        self.name = name  # 商品名称
        self.price = price  # 商品价格
        self.barcode = barcode  # 商品条形码
        self.image_path = image_path  # 商品图片路径

    def __str__(self):
        return f"{self.name} (ID: {self.product_id}) - ￥{self.price:.2f}"

class SupermarketSystem:
    """超市结算系统类，管理商品和结算功能"""
    def __init__(self):
        self.products = {}  # 存储所有商品，key为商品ID或条形码
        # 购物车，使用字典存储 {product_id: [product, quantity]}
        self.cart = {}
        # 确保images目录存在
        self.images_dir = "images"
        if not os.path.exists(self.images_dir):
            os.makedirs(self.images_dir)
        # 数据文件路径
        self.data_file = "products_data.json"
        # 尝试从文件加载数据
        self.load_products()

    def initialize_sample_products(self):
        """初始化一些示例商品"""
        sample_products = [
            Product("001", "可口可乐", 3.5, "6921168509256"),
            Product("002", "百事可乐", 3.5, "6901288050439"),
            Product("003", "农夫山泉", 2.0, "6921168509232"),
            Product("004", "康师傅红烧牛肉面", 4.5, "6921168509249"),
            Product("005", "德芙巧克力", 12.0, "6921168509263")
        ]
        
        for product in sample_products:
            self.add_product(product)
        
        # 保存示例商品数据
        self.save_products()
        
    def load_products(self):
        """从文件加载商品数据"""
        if os.path.exists(self.data_file):
            try:
                with open(self.data_file, 'r', encoding='utf-8') as f:
                    products_data = json.load(f)
                    
                # 清空当前商品列表
                self.products.clear()
                
                # 重建商品对象
                for data in products_data:
                    product = Product(
                        product_id=data['product_id'],
                        name=data['name'],
                        price=data['price'],
                        barcode=data.get('barcode'),
                        image_path=data.get('image_path')
                    )
                    self.add_product(product)
            except Exception as e:
                print(f"加载商品数据失败: {e}")
                messagebox.showerror("错误", f"加载商品数据失败: {str(e)}")
        else:
            # 文件不存在时不初始化示例商品，保持商品列表为空
            print("商品数据文件不存在，初始化为空列表")
            
    def save_products(self):
        """保存商品数据到文件"""
        try:
            # 获取唯一商品列表（避免通过ID和条形码重复保存）
            unique_products = {}
            for product in self.products.values():
                unique_products[product.product_id] = product
                
            # 转换为可序列化的字典列表
            products_data = []
            for product in unique_products.values():
                product_dict = {
                    'product_id': product.product_id,
                    'name': product.name,
                    'price': product.price,
                    'barcode': product.barcode,
                    'image_path': product.image_path
                }
                products_data.append(product_dict)
                
            # 保存到文件
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(products_data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存商品数据失败: {e}")
            messagebox.showerror("错误", f"保存商品数据失败: {str(e)}")
            
    def get_next_product_id(self):
        """生成下一个商品ID（自增功能）"""
        # 获取当前所有商品ID
        product_ids = []
        for product in self.products.values():
            if product.product_id.isdigit():
                product_ids.append(int(product.product_id))
                
        if not product_ids:
            return "001"  # 如果没有商品，从001开始
            
        # 找出最大ID并加1
        max_id = max(product_ids)
        next_id = max_id + 1
        
        # 格式化为3位字符串，不足前面补0
        return f"{next_id:03d}"

    def add_product(self, product):
        """添加商品到系统"""
        self.products[product.product_id] = product
        if product.barcode:
            self.products[product.barcode] = product
    
    def get_image_path(self, product_id):
        """获取商品图片路径"""
        product = self.products.get(product_id)
        if product and product.image_path:
            return product.image_path
        return None

    def identify_product(self, identifier):
        """通过ID或条形码识别商品"""
        return self.products.get(identifier)

    def calculate_total(self):
        """计算购物车总费用"""
        total = 0
        for product, quantity in self.cart.values():
            total += product.price * quantity
        return total

class SupermarketGUI:
    """小超市结算系统图形用户界面"""
    def __init__(self, root):
        self.root = root
        self.root.title("小超市结算系统")
        self.root.geometry("800x600")
        self.root.resizable(True, True)
        
        # 设置中文字体支持
        self.style = ttk.Style()
        # 创建系统实例
        self.system = SupermarketSystem()
        
        # 如果没有商品数据，初始化示例商品
        if len(self.system.products) == 0:
            self.system.initialize_sample_products()
            messagebox.showinfo("初始化", "系统已初始化示例商品")
        
        # 创建主界面
        self.create_main_frame()
        
        # 摄像头相关
        self.cap = None
        self.camera_window = None
        self.current_image_path = None
        
    def create_main_frame(self):
        """创建主界面"""
        # 创建主框架
        self.main_frame = ttk.Frame(self.root, padding="20")
        self.main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建标题
        title_label = ttk.Label(self.main_frame, text="小超市结算系统", font=("SimHei", 20, "bold"))
        title_label.pack(pady=20)
        
        # 创建按钮框架
        button_frame = ttk.Frame(self.main_frame)
        button_frame.pack(pady=20)
        
        # 创建功能按钮
        button_width = 20
        
        self.register_btn = ttk.Button(button_frame, text="注册新商品", 
                                      command=self.register_product_window, width=button_width)
        self.register_btn.grid(row=0, column=0, padx=10, pady=10)
        
        self.view_btn = ttk.Button(button_frame, text="查看所有商品", 
                                  command=self.view_products_window, width=button_width)
        self.view_btn.grid(row=0, column=1, padx=10, pady=10)
        
        self.scan_btn = ttk.Button(button_frame, text="扫描商品", 
                                  command=self.scan_product_window, width=button_width)
        self.scan_btn.grid(row=1, column=0, padx=10, pady=10)
        
        self.checkout_btn = ttk.Button(button_frame, text="结算并打印收据", 
                                      command=self.checkout_window, width=button_width)
        self.checkout_btn.grid(row=1, column=1, padx=10, pady=10)
        
        # 创建购物车状态显示
        self.cart_frame = ttk.LabelFrame(self.main_frame, text="购物车状态")
        self.cart_frame.pack(fill=tk.BOTH, expand=True, pady=20)
        
        self.cart_label = ttk.Label(self.cart_frame, text="购物车为空", font=("SimHei", 12))
        self.cart_label.pack(pady=20)
        
        # 更新购物车状态
        self.update_cart_status()
    
    def _place_buttons_in_treeview(self, tree, widget, item_id):
        """将小部件放置在Treeview的单元格中"""
        try:
            # 获取当前项的索引位置
            item_idx = tree.index(item_id)
            
            # 尝试获取单元格的坐标
            bbox = tree.bbox(item_id, "action")
            
            # 检查是否获取到了有效坐标
            if bbox and len(bbox) == 4:
                x, y, width, height = bbox
                if x != -1 and y != -1:
                    # 计算按钮框架的位置和大小，确保所有行都能正确显示
                    widget.place(in_=tree, x=x+5, y=y+18, anchor="nw")
            else:
                # 获取Treeview的几何信息
                tree_width = tree.winfo_width()
                tree_y = tree.winfo_y()
                
                # 确保所有行都能正确显示，特别是第一行
                if tree_width > 0:
                    # 计算按钮的X位置（在操作列）
                    x_pos = tree_width - 150
                    # 计算按钮的Y位置，根据索引确保所有行都能显示
                    y_pos = tree_y + 22 * (item_idx + 1)  # +1确保按钮在数据行
                    
                    # 放置按钮
                    widget.place(in_=tree, x=x_pos, y=y_pos, anchor="nw")
        except Exception as e:
            # 发生异常时，使用备选方案，确保所有行都能显示按钮
            try:
                # 获取当前项的索引位置
                item_idx = tree.index(item_id)
                
                # 获取Treeview的几何信息
                tree_width = tree.winfo_width()
                tree_y = tree.winfo_y()
                
                # 计算可靠的位置，确保所有行（包括第一行）都能显示
                if tree_width == 0:
                    tree_width = 600  # 使用默认宽度作为备选
                
                # 确保按钮在操作列
                x_pos = tree_width - 150
                # 根据索引位置计算Y坐标，确保第一行也能显示
                y_pos = tree_y + 22 * (item_idx + 1)
                
                # 放置按钮
                widget.place(in_=tree, x=x_pos, y=y_pos, anchor="nw")
            except:
                # 如果所有尝试都失败，使用固定位置
                # 对于不同的行使用不同的Y位置，确保所有行都能看到
                widget.place(in_=tree, x=450, y=50 + 22 * tree.index(item_id), anchor="nw")
            
    def update_cart_status(self):
        """更新购物车状态显示，显示详细商品列表并支持删除和修改数量"""
        # 先清空购物车框架中的所有组件
        for widget in self.cart_frame.winfo_children():
            widget.destroy()
        
        if not self.system.cart:
            # 购物车为空时显示提示信息
            empty_label = ttk.Label(self.cart_frame, text="购物车为空", font=("SimHei", 12))
            empty_label.pack(pady=20)
        else:
            # 创建一个内部框架来容纳Treeview和滚动条
            content_frame = ttk.Frame(self.cart_frame)
            content_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
            
            # 创建Treeview组件显示购物车详细列表
            columns = ("name", "price", "quantity", "subtotal", "action")
            tree = ttk.Treeview(content_frame, columns=columns, show="headings", height=min(10, len(self.system.cart)))
            
            # 设置列标题
            tree.heading("name", text="商品名称")
            tree.heading("price", text="单价")
            tree.heading("quantity", text="数量")
            tree.heading("subtotal", text="小计")
            tree.heading("action", text="操作")
            
            # 设置列宽
            tree.column("name", width=150, anchor=tk.W)
            tree.column("price", width=80, anchor=tk.CENTER)
            tree.column("quantity", width=80, anchor=tk.CENTER)
            tree.column("subtotal", width=100, anchor=tk.CENTER)
            tree.column("action", width=150, anchor=tk.CENTER)
            
            # 添加滚动条
            scrollbar = ttk.Scrollbar(content_frame, orient=tk.VERTICAL, command=tree.yview)
            tree.configure(yscroll=scrollbar.set)
            
            # 添加商品到Treeview
            item_to_id = {}
            for i, (product_id, (product, quantity)) in enumerate(self.system.cart.items()):
                subtotal = product.price * quantity
                item = tree.insert("", tk.END, values=(product.name, f"￥{product.price:.2f}", quantity, f"￥{subtotal:.2f}", ""))
                item_to_id[item] = product_id
            
            # 放置Treeview和滚动条
            tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
            scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
            
            # 创建操作按钮（增加、减少、删除）
            # 减少数量按钮
            def create_decrease_func(pid):
                def decrease_quantity():
                    if pid in self.system.cart and self.system.cart[pid][1] > 1:
                        self.system.cart[pid][1] -= 1
                        self.update_cart_status()
                    elif pid in self.system.cart:
                        # 如果数量为1，删除商品
                        del self.system.cart[pid]
                        self.update_cart_status()
                return decrease_quantity
            
            # 增加数量按钮
            def create_increase_func(pid):
                def increase_quantity():
                    if pid in self.system.cart:
                        self.system.cart[pid][1] += 1
                        self.update_cart_status()
                return increase_quantity
            
            # 删除商品按钮
            def create_delete_func(pid):
                def delete_product():
                    if pid in self.system.cart:
                        del self.system.cart[pid]
                        self.update_cart_status()
                return delete_product
            
            # 创建操作按钮框架，放置在Treeview的"操作"列中
            # 为每个商品创建操作按钮
            for item_id, product_id in item_to_id.items():
                # 获取商品信息
                product, quantity = self.system.cart[product_id]
                
                # 创建一个框架来放置操作按钮
                action_frame = ttk.Frame(tree)
                
                # 减少按钮
                decrease_btn = ttk.Button(action_frame, text="-", width=3, 
                                        command=create_decrease_func(product_id))
                decrease_btn.pack(side=tk.LEFT, padx=2)
                
                # 增加按钮
                increase_btn = ttk.Button(action_frame, text="+", width=3, 
                                        command=create_increase_func(product_id))
                increase_btn.pack(side=tk.LEFT, padx=2)
                
                # 删除按钮
                delete_btn = ttk.Button(action_frame, text="删除", width=6, 
                                      command=create_delete_func(product_id))
                delete_btn.pack(side=tk.LEFT, padx=5)
                
                # 将按钮框架放置在Treeview单元格中
                tree.set(item_id, "action", "")  # 清空文本
                tree.bind('<Configure>', lambda e: self._place_buttons_in_treeview(tree, action_frame, item_id))
                
                # 手动触发一次配置事件，确保按钮被放置
                tree.event_generate('<Configure>')
            
            # 显示购物车总计
            total = self.system.calculate_total()
            total_label = ttk.Label(self.cart_frame, text=f"总计: ￥{total:.2f}", 
                                  font=("SimHei", 12, "bold"))
            total_label.pack(pady=10, side=tk.BOTTOM, anchor=tk.E, padx=20)
    
    def register_product_window(self):
        """注册新商品窗口"""
        # 创建注册商品窗口
        register_window = tk.Toplevel(self.root)
        register_window.title("注册新商品")
        register_window.geometry("600x500")
        register_window.resizable(False, False)
        register_window.grab_set()  # 模态窗口
        
        # 创建框架
        frame = ttk.Frame(register_window, padding="20")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 商品ID（自动生成，不可编辑）
        next_id = self.system.get_next_product_id()
        ttk.Label(frame, text="商品ID:", font=("SimHei", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        id_entry = ttk.Entry(frame, width=30)
        id_entry.grid(row=0, column=1, pady=5)
        id_entry.insert(0, next_id)
        id_entry.config(state=tk.DISABLED)  # 禁用手动修改
        
        # 商品名称输入
        ttk.Label(frame, text="商品名称:", font=("SimHei", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        name_entry = ttk.Entry(frame, width=30)
        name_entry.grid(row=1, column=1, pady=5)
        
        # 商品价格输入
        ttk.Label(frame, text="商品价格:", font=("SimHei", 10)).grid(row=2, column=0, sticky=tk.W, pady=5)
        price_entry = ttk.Entry(frame, width=30)
        price_entry.grid(row=2, column=1, pady=5)
        
        # 商品条形码输入
        ttk.Label(frame, text="条形码 (可选):", font=("SimHei", 10)).grid(row=3, column=0, sticky=tk.W, pady=5)
        barcode_entry = ttk.Entry(frame, width=30)
        barcode_entry.grid(row=3, column=1, pady=5)
        
        # 商品图片
        ttk.Label(frame, text="商品图片:", font=("SimHei", 10)).grid(row=4, column=0, sticky=tk.W, pady=5)
        
        # 图片预览区域
        preview_frame = ttk.Frame(frame, width=200, height=200)
        preview_frame.grid(row=4, column=1, pady=5)
        preview_frame.grid_propagate(False)
        
        # 图片预览标签
        self.preview_label = ttk.Label(preview_frame)
        self.preview_label.pack(fill=tk.BOTH, expand=True)
        
        # 当前注册窗口的图片路径
        current_image_path = [None]  # 使用列表作为可变对象
        
        # 拍照按钮
        def take_photo():
            # 打开摄像头拍照
            self.open_camera(register_window, current_image_path, self.preview_label)
        
        ttk.Button(frame, text="拍照录入", command=take_photo).grid(row=5, column=0, columnspan=2, pady=10)
        
        # 注册按钮
        def register_product():
            product_id = id_entry.get().strip()
            name = name_entry.get().strip()
            price_text = price_entry.get().strip()
            barcode = barcode_entry.get().strip()
            image_path = current_image_path[0]
            
            # 验证输入
            if not product_id or not name or not price_text:
                messagebox.showerror("输入错误", "商品ID、名称和价格不能为空！")
                return
            
            try:
                price = float(price_text)
                if price < 0:
                    messagebox.showerror("输入错误", "价格不能为负数！")
                    return
            except ValueError:
                messagebox.showerror("输入错误", "请输入有效的数字价格！")
                return
            
            # 检查商品ID是否已存在
            if product_id in self.system.products:
                messagebox.showerror("注册失败", "商品ID已存在！")
                return
            
            # 检查条形码是否已存在（如果输入了条形码）
            if barcode and barcode in self.system.products:
                messagebox.showerror("注册失败", "条形码已存在！")
                return
            
            # 创建并添加商品
            new_product = Product(product_id, name, price, barcode if barcode else None, image_path)
            self.system.add_product(new_product)
            
            # 保存商品数据
            self.system.save_products()
            
            messagebox.showinfo("注册成功", f"商品 '{name}' 注册成功！")
            register_window.destroy()
        
        # 创建注册和取消按钮
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=4, column=0, columnspan=2, pady=20)
        
        ttk.Button(button_frame, text="注册", command=register_product).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=register_window.destroy).pack(side=tk.LEFT, padx=10)
    
    def view_products_window(self):
        """查看所有商品窗口"""
        # 创建查看商品窗口
        view_window = tk.Toplevel(self.root)
        view_window.title("所有商品列表")
        view_window.geometry("800x500")
        view_window.resizable(True, True)
        
        # 创建框架
        frame = ttk.Frame(view_window, padding="20")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建Treeview组件显示商品列表
        columns = ("id", "name", "price", "barcode")
        tree = ttk.Treeview(frame, columns=columns, show="headings")
        
        # 设置列标题
        tree.heading("id", text="商品ID")
        tree.heading("name", text="商品名称")
        tree.heading("price", text="价格")
        tree.heading("barcode", text="条形码")
        
        # 设置列宽
        tree.column("id", width=80, anchor=tk.CENTER)
        tree.column("name", width=150, anchor=tk.W)
        tree.column("price", width=80, anchor=tk.CENTER)
        tree.column("barcode", width=150, anchor=tk.CENTER)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=tree.yview)
        tree.configure(yscroll=scrollbar.set)
        
        # 获取唯一商品列表（避免通过ID和条形码重复显示）
        unique_products = {}
        for product in self.system.products.values():
            unique_products[product.product_id] = product
        
        # 添加商品数据到Treeview
        for pid, product in unique_products.items():
            tree.insert("", tk.END, values=(product.product_id, product.name, 
                                          f"￥{product.price:.2f}", 
                                          product.barcode if product.barcode else ""))
        
        # 双击查看商品详情（含图片）
        def on_item_double_click(event):
            item = tree.selection()[0] if tree.selection() else None
            if item:
                product_id = tree.item(item, "values")[0]
                self.view_product_detail(product_id)
        
        tree.bind("<Double-1>", on_item_double_click)
        
        # 创建底部框架
        bottom_frame = ttk.Frame(frame)
        bottom_frame.pack(fill=tk.X, pady=10)
        
        # 添加查看详情按钮
        ttk.Button(bottom_frame, text="查看详情", command=lambda: 
                   on_item_double_click(None) if tree.selection() else 
                   messagebox.showinfo("提示", "请先选择一个商品")).pack(side=tk.RIGHT, padx=10)
        
        # 添加关闭按钮
        ttk.Button(bottom_frame, text="关闭", command=view_window.destroy).pack(side=tk.RIGHT, padx=10)
        
        # 放置Treeview和滚动条
        tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, pady=(0, 10))
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=(0, 10))
    
    def view_product_detail(self, product_id):
        """查看商品详细信息（含图片）"""
        product = self.system.products.get(product_id)
        if not product:
            messagebox.showerror("错误", "未找到该商品！")
            return
        
        # 创建商品详情窗口
        detail_window = tk.Toplevel(self.root)
        detail_window.title(f"商品详情 - {product.name}")
        detail_window.geometry("500x400")
        detail_window.resizable(False, False)
        
        # 创建框架
        frame = ttk.Frame(detail_window, padding="20")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 左侧：图片显示
        left_frame = ttk.Frame(frame, width=200, height=200)
        left_frame.pack(side=tk.LEFT, padx=10, pady=10)
        left_frame.pack_propagate(False)
        
        # 图片标签
        image_label = ttk.Label(left_frame)
        image_label.pack(fill=tk.BOTH, expand=True)
        
        # 加载并显示商品图片
        if product.image_path and os.path.exists(product.image_path):
            self.update_image_preview(image_label, product.image_path)
        else:
            # 没有图片时显示占位文本
            image_label.config(text="暂无图片", font=("SimHei", 12))
        
        # 右侧：商品信息
        right_frame = ttk.Frame(frame)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 商品信息标签
        ttk.Label(right_frame, text="商品ID:", font=("SimHei", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
        ttk.Label(right_frame, text=product.product_id, font=("SimHei", 10)).grid(row=0, column=1, sticky=tk.W, pady=5)
        
        ttk.Label(right_frame, text="商品名称:", font=("SimHei", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
        ttk.Label(right_frame, text=product.name, font=("SimHei", 10)).grid(row=1, column=1, sticky=tk.W, pady=5)
        
        ttk.Label(right_frame, text="商品价格:", font=("SimHei", 10)).grid(row=2, column=0, sticky=tk.W, pady=5)
        ttk.Label(right_frame, text=f"￥{product.price:.2f}", font=("SimHei", 10)).grid(row=2, column=1, sticky=tk.W, pady=5)
        
        ttk.Label(right_frame, text="条形码:", font=("SimHei", 10)).grid(row=3, column=0, sticky=tk.W, pady=5)
        ttk.Label(right_frame, text=product.barcode if product.barcode else "无", font=("SimHei", 10)).grid(row=3, column=1, sticky=tk.W, pady=5)
        
        # 修改商品信息
        def modify_product():
            # 创建修改商品窗口
            modify_window = tk.Toplevel(detail_window)
            modify_window.title(f"修改商品 - {product.name}")
            modify_window.geometry("500x400")
            modify_window.resizable(False, False)
            
            # 创建框架
            modify_frame = ttk.Frame(modify_window, padding="20")
            modify_frame.pack(fill=tk.BOTH, expand=True)
            
            # 商品ID（不可修改）
            ttk.Label(modify_frame, text="商品ID:", font=("SimHei", 10)).grid(row=0, column=0, sticky=tk.W, pady=5)
            ttk.Label(modify_frame, text=product.product_id, font=("SimHei", 10)).grid(row=0, column=1, sticky=tk.W, pady=5)
            
            # 商品名称输入
            ttk.Label(modify_frame, text="商品名称:", font=("SimHei", 10)).grid(row=1, column=0, sticky=tk.W, pady=5)
            name_var = tk.StringVar(value=product.name)
            name_entry = ttk.Entry(modify_frame, textvariable=name_var, width=30)
            name_entry.grid(row=1, column=1, pady=5)
            
            # 商品价格输入
            ttk.Label(modify_frame, text="商品价格:", font=("SimHei", 10)).grid(row=2, column=0, sticky=tk.W, pady=5)
            price_var = tk.StringVar(value=str(product.price))
            price_entry = ttk.Entry(modify_frame, textvariable=price_var, width=30)
            price_entry.grid(row=2, column=1, pady=5)
            
            # 商品条形码输入
            ttk.Label(modify_frame, text="条形码:", font=("SimHei", 10)).grid(row=3, column=0, sticky=tk.W, pady=5)
            barcode_var = tk.StringVar(value=product.barcode if product.barcode else "")
            barcode_entry = ttk.Entry(modify_frame, textvariable=barcode_var, width=30)
            barcode_entry.grid(row=3, column=1, pady=5)
            
            # 保存修改
            def save_changes():
                name = name_var.get().strip()
                price_text = price_var.get().strip()
                barcode = barcode_var.get().strip()
                
                # 验证输入
                if not name or not price_text:
                    messagebox.showerror("输入错误", "商品名称和价格不能为空！")
                    return
                
                try:
                    price = float(price_text)
                    if price < 0:
                        messagebox.showerror("输入错误", "价格不能为负数！")
                        return
                except ValueError:
                    messagebox.showerror("输入错误", "请输入有效的数字价格！")
                    return
                
                # 检查条形码是否已被其他商品使用（如果有条形码）
                barcode_exists = False
                if barcode:
                    for pid, p in self.system.products.items():
                        if pid != product.product_id and p.product_id != product.product_id:
                            if p.barcode == barcode:
                                barcode_exists = True
                                break
                
                if barcode_exists:
                    messagebox.showerror("修改失败", "该条形码已被其他商品使用！")
                    return
                
                # 更新商品信息
                old_barcode = product.barcode
                product.name = name
                product.price = price
                product.barcode = barcode if barcode else None
                
                # 更新products字典（ID作为key的条目）
                self.system.products[product.product_id] = product
                
                # 更新或删除条形码条目
                if old_barcode:
                    if old_barcode in self.system.products:
                        del self.system.products[old_barcode]
                if barcode:
                    self.system.products[barcode] = product
                
                # 保存商品数据
                self.system.save_products()
                
                # 更新详情窗口显示
                detail_window.title(f"商品详情 - {product.name}")
                ttk.Label(right_frame, text=product.name, font=("SimHei", 10)).grid(row=1, column=1, sticky=tk.W, pady=5)
                ttk.Label(right_frame, text=f"￥{product.price:.2f}", font=("SimHei", 10)).grid(row=2, column=1, sticky=tk.W, pady=5)
                ttk.Label(right_frame, text=product.barcode if product.barcode else "无", font=("SimHei", 10)).grid(row=3, column=1, sticky=tk.W, pady=5)
                
                messagebox.showinfo("修改成功", f"商品 '{name}' 修改成功！")
                modify_window.destroy()
            
            # 底部按钮
            button_frame = ttk.Frame(modify_frame)
            button_frame.grid(row=4, column=0, columnspan=2, pady=20)
            
            ttk.Button(button_frame, text="保存修改", command=save_changes).pack(side=tk.LEFT, padx=10)
            ttk.Button(button_frame, text="取消", command=modify_window.destroy).pack(side=tk.LEFT, padx=10)
        
        # 底部按钮框架
        bottom_button_frame = ttk.Frame(frame)
        bottom_button_frame.pack(pady=10, side=tk.BOTTOM)
        
        # 修改按钮
        ttk.Button(bottom_button_frame, text="修改商品", command=modify_product).pack(side=tk.LEFT, padx=10)
        # 关闭按钮
        ttk.Button(bottom_button_frame, text="关闭", command=detail_window.destroy).pack(side=tk.LEFT, padx=10)
    
    def scan_product_window(self):
        """扫描商品窗口"""
        # 创建扫描商品窗口
        scan_window = tk.Toplevel(self.root)
        scan_window.title("扫描商品")
        scan_window.geometry("400x200")
        scan_window.resizable(False, False)
        scan_window.grab_set()  # 模态窗口
        
        # 创建框架
        frame = ttk.Frame(scan_window, padding="20")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 输入框
        ttk.Label(frame, text="请输入商品ID或条形码:", font=("SimHei", 10)).pack(pady=10)
        entry = ttk.Entry(frame, width=40, font=("SimHei", 12))
        entry.pack(pady=10)
        entry.focus_set()  # 自动聚焦
        
        # 扫描按钮
        def scan_product():
            identifier = entry.get().strip()
            if not identifier:
                messagebox.showwarning("输入错误", "请输入商品ID或条形码！")
                return
            
            product = self.system.identify_product(identifier)
            
            if product:
                # 如果商品已在购物车中，增加数量；否则添加新商品
                if product.product_id in self.system.cart:
                    self.system.cart[product.product_id][1] += 1
                    messagebox.showinfo("扫描成功", f"已增加 {product.name} 数量至: {self.system.cart[product.product_id][1]}")
                else:
                    self.system.cart[product.product_id] = [product, 1]
                    messagebox.showinfo("扫描成功", f"已添加: {product.name} - ￥{product.price:.2f}")
                
                self.update_cart_status()  # 更新购物车状态
                entry.delete(0, tk.END)  # 清空输入框
                entry.focus_set()  # 重新聚焦
            else:
                messagebox.showerror("扫描失败", "未找到该商品，请检查输入或先注册该商品！")
        
        # 绑定回车键执行扫描
        scan_window.bind("<Return>", lambda event: scan_product())
        
        # 创建按钮框架
        button_frame = ttk.Frame(frame)
        button_frame.pack(pady=10)
        
        ttk.Button(button_frame, text="扫描", command=scan_product).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="完成", command=scan_window.destroy).pack(side=tk.LEFT, padx=10)
    
    def open_camera(self, parent_window, current_image_path, preview_label):
        """打开摄像头进行拍照"""
        # 如果已经有摄像头窗口打开，先关闭
        if self.camera_window and self.camera_window.winfo_exists():
            self.camera_window.destroy()
        
        # 尝试打开摄像头
        self.cap = cv2.VideoCapture(0)
        if not self.cap.isOpened():
            messagebox.showerror("错误", "无法打开摄像头！")
            return
        
        # 创建摄像头窗口
        self.camera_window = tk.Toplevel(parent_window)
        self.camera_window.title("商品拍照")
        self.camera_window.geometry("640x480")
        self.camera_window.resizable(False, False)
        
        # 创建视频显示区域
        self.camera_label = ttk.Label(self.camera_window)
        self.camera_label.pack()
        
        # 创建按钮框架
        button_frame = ttk.Frame(self.camera_window)
        button_frame.pack(pady=10)
        
        # 拍照按钮
        def capture_photo():
            if self.cap and self.cap.isOpened():
                ret, frame = self.cap.read()
                if ret:
                    # 生成唯一的文件名
                    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
                    unique_id = str(uuid.uuid4())[:8]
                    filename = f"{timestamp}_{unique_id}.jpg"
                    image_path = os.path.join(self.system.images_dir, filename)
                    
                    # 保存图片
                    cv2.imwrite(image_path, frame)
                    
                    # 更新当前图片路径
                    current_image_path[0] = image_path
                    
                    # 更新预览
                    self.update_image_preview(preview_label, image_path)
                    
                    messagebox.showinfo("拍照成功", "商品照片已保存！")
                    self.close_camera()
        
        # 关闭按钮
        def close_camera_window():
            self.close_camera()
        
        ttk.Button(button_frame, text="拍照", command=capture_photo).pack(side=tk.LEFT, padx=10)
        ttk.Button(button_frame, text="取消", command=close_camera_window).pack(side=tk.LEFT, padx=10)
        
        # 开始显示视频
        self.show_video()
    
    def show_video(self):
        """显示摄像头视频"""
        if self.cap and self.cap.isOpened() and self.camera_window and self.camera_window.winfo_exists():
            ret, frame = self.cap.read()
            if ret:
                # 转换颜色空间
                rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                
                # 转换为PIL图像
                pil_image = Image.fromarray(rgb_frame)
                
                # 调整大小以适应窗口
                window_width = 640
                window_height = 400
                pil_image = pil_image.resize((window_width, window_height), Image.LANCZOS)
                
                # 转换为Tkinter可用的图像
                tk_image = ImageTk.PhotoImage(image=pil_image)
                
                # 更新标签
                self.camera_label.imgtk = tk_image
                self.camera_label.configure(image=tk_image)
                
                # 继续显示下一帧
                self.camera_window.after(10, self.show_video)
    
    def close_camera(self):
        """关闭摄像头"""
        if self.cap:
            self.cap.release()
            self.cap = None
        if self.camera_window and self.camera_window.winfo_exists():
            self.camera_window.destroy()
    
    def update_image_preview(self, preview_label, image_path):
        """更新图片预览"""
        if os.path.exists(image_path):
            # 打开图片
            pil_image = Image.open(image_path)
            
            # 调整大小以适应预览区域
            preview_width = 200
            preview_height = 200
            pil_image = pil_image.resize((preview_width, preview_height), Image.LANCZOS)
            
            # 转换为Tkinter可用的图像
            tk_image = ImageTk.PhotoImage(image=pil_image)
            
            # 更新预览标签
            preview_label.imgtk = tk_image
            preview_label.configure(image=tk_image)
    
    def checkout_window(self):
        """结算窗口"""
        if not self.system.cart:
            messagebox.showinfo("结算", "购物车为空！")
            return
        
        # 创建结算窗口
        checkout_window = tk.Toplevel(self.root)
        checkout_window.title("结算")
        checkout_window.geometry("500x400")
        checkout_window.resizable(True, True)
        
        # 创建框架
        frame = ttk.Frame(checkout_window, padding="20")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建购物清单标题
        ttk.Label(frame, text="购物清单", font=("SimHei", 16, "bold")).pack(pady=10)
        
        # 创建收据文本框
        receipt_text = tk.Text(frame, width=60, height=15, font=("SimHei", 10))
        receipt_text.pack(pady=10, fill=tk.BOTH, expand=True)
        receipt_text.config(state=tk.DISABLED)  # 只读
        
        # 生成收据内容（直接使用购物车字典中的数据，已经包含数量信息）
        receipt_content = "\n===== 购物清单 =====\n"
        
        for product_id, (product, quantity) in self.system.cart.items():
            subtotal = product.price * quantity
            receipt_content += f"{product.name} x{quantity} - ￥{product.price:.2f} x{quantity} = ￥{subtotal:.2f}\n"
        
        # 计算并添加总计
        total = self.system.calculate_total()
        receipt_content += "=" * 30 + "\n"
        receipt_content += f"总计: ￥{total:.2f}\n"
        receipt_content += "=" * 30 + "\n"
        
        # 显示收据内容
        receipt_text.config(state=tk.NORMAL)
        receipt_text.insert(tk.END, receipt_content)
        receipt_text.config(state=tk.DISABLED)
        
        # 完成结算按钮
        def complete_checkout():
            messagebox.showinfo("结算完成", "谢谢惠顾！")
            self.system.cart = {}  # 清空购物车
            self.update_cart_status()  # 更新购物车状态
            checkout_window.destroy()
        
        ttk.Button(frame, text="完成结算", command=complete_checkout).pack(pady=10)

if __name__ == "__main__":
    # 创建Tkinter根窗口
    root = tk.Tk()
    # 设置中文字体支持
    # 创建并运行超市结算系统GUI
    app = SupermarketGUI(root)
    
    # 添加窗口关闭事件处理，确保数据保存
    def on_closing():
        try:
            app.system.save_products()
        except Exception as e:
            print(f"关闭时保存数据失败: {e}")
        root.destroy()
    
    root.protocol("WM_DELETE_WINDOW", on_closing)
    
    # 运行主循环
    root.mainloop()